﻿#pragma once
//安放公共的东西

#include <iostream>
#include <vector>
#include <algorithm>
#include <time.h>
#include <stdio.h>
#include <assert.h>
#include <thread>
#include <mutex>
#include <stdlib.h>
#include <atomic>
#include "CentralCache.h"
using std::cout;
using std::endl;
using std::min;




static const int MAX_BYTES = 256 * 1024;
static const int NFREELISTS = 208;
static const size_t NPAGES = 129;
static const size_t PAGESHIFT = 13;


#ifdef _WIN64
	typedef unsigned long long PAGE_ID;
#elif _WIN32
	typedef size_t PAGE_ID;
#else
	//linux
#endif

// 直接去堆上按页申请空间
inline static void* SystemAlloc(size_t kpage)
{
#ifdef _WIN32
		void* ptr = VirtualAlloc(0, kpage << 13, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
#else
		// linux下brk mmap等
#endif
	if (ptr == nullptr)
		throw std::bad_alloc();

	return ptr;
}

inline static void SystemFree(void* ptr)
{
#ifdef _WIN32
	VirtualFree(ptr, 0, MEM_RELEASE);
#else
	// sbrk unmmap等
#endif
}

static void*& Next_Obj(void* obj)
{
	return *(void**)obj;//为了平台匹配。因为64位和32位指针的大小不同，设置为
} 

// 管理切分好的小对象的自由链表
class FreeList
{
public:
	void Push(void* obj)//头插
	{
		assert(obj);
		Next_Obj(obj) = _freeList;
		_freeList = obj;
		++_size;
	}

	void* Pop()//头删
	{
		assert(_freeList);

		void* obj = _freeList;
		_freeList = Next_Obj(obj);
		return obj;
	}

	void PushRange(void* start, void* end, size_t n)//插入一段数据
	{
		NextObj(end) = _freeList;
		_freeList = start;
		_size += n;
	}

	void PopRange(void*& start, void*& end, size_t n)//删除一段数据
	{
		assert(n <= _size);
		start = _freeList;
		end = start;

		for (size_t i = 0; i < n - 1; ++i)
		{
			end = NextObj(end);
		}

		_freeList = NextObj(end);
		NextObj(end) = nullptr;
		_size -= n;
	}

	bool Empty()
	{
		return _freeList == nullptr;
	}

	size_t& MaxSize()//返回值搞成引用类型，就是左值了。后续进行++，--等操作不会报错
	{
		return _maxSize;
	}

	size_t Size()
	{
		return _size;
	}
private:
	void* _freeList=nullptr;
	size_t _maxSize = 1;
	size_t _size = 0;
};


//计算大小对齐规则 
class SizeClass
{
public:
	//整体控制10%左右内碎片浪费

	static inline size_t _RoundUp(size_t size, size_t alignNum)
	{
		//size_t alignSize;
		//if (size % alignNum != 0)
		//{
		//	alignSize = (size / alignNum + 1)*alignNum;
		//}
		//else
		//{
		//	alignSize = size;
		//}
		//return alignSize;

		return ((size + alignNum - 1) & ~(alignNum - 1));
	}


	//计算申请对应内存，所分配的字节数
	static inline size_t RoundUp(size_t size)
	{
		//保持10%内碎片
		// [1,128] 8byte对⻬ freelist[0,16)
		// [128+1,1024] 16byte对⻬ freelist[16,72)
		// [1024+1,8*1024] 128byte对⻬ freelist[72,128)
		// [8*1024+1,64*1024] 1024byte对⻬ freelist[128,184)
		// [64*1024+1,256*1024] 8*1024byte对⻬ freelist[184,208)
		if (size <= 128)
		{
			return _RoundUp(size, 8);
		}
		else if (size <= 1024)
		{
			return _RoundUp(size, 16);
		}
		else if (size <= 8 * 1024)
		{
			return _RoundUp(size, 128);
		}
		else if (size <= 64 * 1024)
		{
			return _RoundUp(size, 1024);
		}
		else if (size <= 256 * 1024)//256KB
		{
			return _RoundUp(size, 8 * 1024);
		}
		else
		{
			assert(0);
			return -1;
		}
	}

	static inline size_t _Index(size_t bytes, size_t align_shift)//传递次方数，进行位运算
	{
		return ((bytes + (1 << align_shift) - 1) >> align_shift) - 1;
	}

	// 计算映射的哪⼀个⾃由链表桶
	static inline size_t Index(size_t bytes)
	{
		assert(bytes <= MAX_BYTES);
		// 每个区间有多少个链
		static int group_array[4] = { 16, 56, 56, 56 };
		if (bytes <= 128) {
			return _Index(bytes, 3);//进行位运算
		}
		else if (bytes <= 1024) {
			return _Index(bytes - 128, 4) + group_array[0];
		}
		else if (bytes <= 8 * 1024) {
			return _Index(bytes - 1024, 7) + group_array[1] + group_array[0];
		}
		else if (bytes <= 64 * 1024) {
			return _Index(bytes - 8 * 1024, 10) + group_array[2] + group_array[1] + group_array[0];
		}
		else if (bytes <= 256 * 1024) {
			return _Index(bytes - 64 * 1024, 13) + group_array[3] + group_array[2] + group_array[1] + group_array[0];
		}
		else {
			assert(false);
		}
		return -1;
	}
	//每一次从centralcache获取的字节数
	static size_t NumMoveSize(size_t size)
	{
		assert(size > 0);
		if (size == 0)
			return 0;
		int num = MAX_BYTES / size;
		if (num < 2)
			num = 2;
		if (num > 512)
			num = 512;

		return num;
	}

// 计算一次向系统获取几个页
// 单个对象 8byte
// ...
// 单个对象 256KB
	static size_t NumMovePage(size_t size)
	{
		size_t num = NumMoveSize(size);
		size_t npage = num * size;

		npage >>= PAGESHIFT;
		if (npage == 0)
			npage = 1;

		return npage;
	}

};


//span结构：管理多个连续页大块内存跨度结构
struct Span
{
	//2^32/ 2^13=2^19   以8kb为一页
	//2^64/2^13=2^51    
	//不同平台下，页数的范围大小是不一样的，因此需要做区分，用#ifdef #elif #elif #endif
	PAGE_ID _pageId;   //大块内存起始页号
	size_t _n;       //页数量

	Span* _next=nullptr;    //双向链表结构
	Span* _prev=nullptr;

	size_t _objSize = 0;  // 切好的小对象的大小
	size_t _useCount=0;   //切好小块内存，使用计数，当==0时，说明threadcache所申请对象全部还回来了，可以还给Pagecache了
	void* _freeList=nullptr;      //切好的小块内存自由链表

	bool _isUse = false;          // bool记录是否在被使用
};


//带头双向循环链表
class SpanList
{
public:
	SpanList()
	{
		static ObjectPool<Span> spanPool;
		_head = spanPool.New();
		_head->_next = _head;
		_head->_prev = _head;
	}
	void Insert(Span* pos, Span* newSpan)//在pos前加入newSpan
	{
		assert(pos);
		assert(newSpan);

		Span* prev = pos->_prev;

		prev->_next = newSpan;
		newSpan->_prev = prev;
		newSpan->_next = pos;
		pos->_prev = newSpan;
	}
	void Erase(Span* pos)
	{
		assert(pos);
		assert(pos != _head);//不能删除哨兵位头节点

		Span* prev = pos->_prev;
		Span* next = pos->_next;

		prev->_next = next;
		next->_prev = prev;
	}

	Span* Begin()
	{
		return _head->_next;
	}

	Span* End()
	{
		return _head;
	}

	bool Empty()
	{
		return _head->_next == _head;
	}

	void PushFront(Span* span)
	{
		Insert(_head->_next, span);
	}
	Span* PopFront()
	{
		Span* front = _head->_next;
		Erase(front);

		return front;
	}



private:
	Span* _head;//带头双向循环链表

public:
	std::mutex _mtx;    //加锁（桶锁）
};



  